﻿using EditoneLib.Streams;
using System;
using System.Collections.Generic;
using System.Linq;

namespace EditoneLib
{
    public abstract class BaseAudioTrack<TClip> : BaseTrack, IAudioTrack where TClip : BaseAudioClip
    {
        private float _volume;

        public BaseAudioTrack()
            : base()
        {
            Volume = 1.0f;
        }

        public abstract int NumChannels { get; }

        public float Volume
        {
            get { return _volume; }
            set
            {
                _volume = value;
                OnPropertyChanged();
            }
        }

        public virtual TClip ConcatenateClips(TClip clip1, TClip clip2)
        {
            TimeSpan time1 = this.Single(pair => pair.Value == clip1).Key;
            TimeSpan time2 = this.Single(pair => pair.Value == clip2).Key;

            if (clip1.NumChannels != clip2.NumChannels)
            {
                throw new ArgumentException("Clips must have same channel count.", "clip1");
            }

            if (Settings.ToSampleCount(time1 + clip1.TotalLength) / clip1.NumChannels
                != Settings.ToSampleCount(time2) / clip2.NumChannels)
                throw new ArgumentException("Clips must be neighbors. Clip1 must be directly left of clip2.", "clip1");

            var newClip =
                (TClip)
                    Activator.CreateInstance(typeof(TClip), new CombinedStream(new[] { clip1.Stream, clip2.Stream }));

            Remove(time2);
            this[time1] = newClip;

            return newClip;
        }

        public abstract void MapDefault(ChannelMapping mapping);

        public virtual Tuple<TClip, TClip> SplitClip(TimeSpan at)
        {
            if (this.ContainsKey(at))
            {
                throw new InvalidOperationException("A clip with this starting offset already exists.");
            }


            KeyValuePair<TimeSpan, TClip> pair =
                this.Select(kvp => new KeyValuePair<TimeSpan, TClip>(kvp.Key, (TClip)kvp.Value))
                    .FirstOrDefault(p => (at >= p.Key) && (at < (p.Key + p.Value.TotalLength)));

            Tuple<BaseAudioClip, BaseAudioClip> tuple = pair.Value.Split(at - pair.Key);

            Remove(pair.Key);
            Add(pair.Key, tuple.Item1);
            Add(at, tuple.Item2);

            return new Tuple<TClip, TClip>((TClip)tuple.Item1, (TClip)tuple.Item2);
        }
    }
}